using System;
using System.Reflection;
using Common.Core;
using Microsoft.Practices.ObjectBuilder2;

namespace Common.Unity.Extensions.Entity
{
	public abstract class EntityContextCreatorBase<EntityContextType> : IEntityCreator
	{
		readonly EntityContextType entityContext;

		protected EntityContextCreatorBase( EntityContextType entityContext )
		{
			this.entityContext = entityContext;
		}

		protected EntityContextType EntityContext
		{
			get { return entityContext; }
		}

		protected virtual void OnCreate( object instance )
		{}

		protected virtual void OnCreated( object instance )
		{}


		static void EnsureDefaultValues( IBuilderContext context )
		{
			var type = context.Existing.GetType();
			foreach ( var attribute in type.GetAttributes<DefaultPropertyValueAttributeBase>() )
			{
				var info = type.GetProperty( attribute.PropertyName );
				if ( info != null )
				{
					object value = attribute.GetValue( info, context ),
					       current = info.GetValue( context.Existing, null );
					if ( !Equals( current, value ) )
					{
						info.SetValue( context.Existing, value, null );
					}
					continue;
				}
				throw new InvalidOperationException( string.Format( "Could not find the property name '{0}' on type '{1}'.", attribute.PropertyName, type.FullName ) );
			}
		}

		object IEntityCreator.CreateEntity( IBuilderContext context )
		{
			var creator =
				context.Policies.Get<IBuildPlanCreatorPolicy>( context.BuildKey );
			if( creator != null )
			{
				var plan = creator.CreatePlan( context, context.BuildKey );
				if ( plan != null )
				{
					plan.BuildUp( context );
				}
			}

			var result = context.Existing;
			if ( result != null )
			{
				OnCreate( result );
				EnsureDefaultValues( context );
				OnCreated( result );
			}
			return result;
		}
	}
}